package com.yunkeji.api.common.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.yunkeji.api.common.bo.AliCallBackBo;
import com.yunkeji.api.common.service.ISysOssService;
import com.yunkeji.common.core.bo.FileUpload;
import com.yunkeji.common.core.domain.vo.SysOssVo;
import com.yunkeji.common.enums.FileTypeEnum;
import com.yunkeji.common.exception.ServiceException;
import com.yunkeji.common.helper.LoginHelper;
import com.yunkeji.common.utils.StringUtils;
import com.yunkeji.dao.domain.sys.SysOss;
import com.yunkeji.dao.mapper.sys.SysOssMapper;
import com.yunkeji.oss.core.OssClient;
import com.yunkeji.oss.entity.UploadResult;
import com.yunkeji.oss.enumd.AccessPolicyType;
import com.yunkeji.oss.factory.OssFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.sql.Date;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 文件上传 服务层实现
 *
 * @author Lion Li
 */
@RequiredArgsConstructor
@Service
public class SysOssServiceImpl implements ISysOssService {

    private final SysOssMapper baseMapper;

    @Override
    public SysOssVo upload(MultipartFile file, String path) {
        String originalfileName = file.getOriginalFilename();
        String suffix =
                StringUtils.substring(
                        originalfileName,
                        originalfileName.lastIndexOf("."),
                        originalfileName.length());
        OssClient storage = OssFactory.instance();
        UploadResult uploadResult;
        try {
            uploadResult =
                    storage.uploadSuffix(file.getBytes(), suffix, file.getContentType(), path);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
        // 保存文件信息
        return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult);
    }

    @Override
    public Map<String, String> upload(Integer fileType, String md5) {

        String prefix =
                FileTypeEnum.getPathByCode(fileType)
                        .replace("evn", SpringUtil.getActiveProfile())
                        .replace("uid", LoginHelper.getPlatformId().toString());
        OssClient storage = OssFactory.instance();
        String accessId = storage.properties.getAccessKey(); // 请填写您的AccessKeyId。
        String accessKey = storage.properties.getSecretKey(); // 请填写您的AccessKeySecret。
        String endpoint = storage.properties.getEndpoint(); // 请填写您的 endpoint。
        String bucket = storage.properties.getBucketName(); // 请填写您的 bucketname 。
        String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
        // callbackUrl为 上传回调服务器的URL，请将下面的IP和Port配置为您自己的真实信息。
        String callbackUrl = storage.properties.getCallbackUrl();

        String dir = prefix + storage.properties.getPrefix(); // 用户上传文件时指定的前缀。
        dir = storage.getPath(dir, "", md5);

        OSSClient client = new OSSClient(endpoint, accessId, accessKey);
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = client.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = client.calculatePostSignature(postPolicy);

            Map<String, String> respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);

            respMap.put("bucket", bucket);
            respMap.put("endpoint", endpoint);

            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));
            JSONObject jasonCallback = JSONUtil.createObj();
            jasonCallback.put("callbackUrl", callbackUrl);
            jasonCallback.put(
                    "callbackBody",
                    "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
            jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
            String base64CallbackBody =
                    BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
            respMap.put("callback", base64CallbackBody);
            return respMap;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("上传异常");
        }
    }

    @Override
    public List<Map<String, String>> upload(FileUpload fileUpload) {
        List<Map<String, String>> res = new ArrayList<>();
        fileUpload
                .getFiles()
                .forEach(item -> res.add(this.upload(item.getFileType(), item.getFileMd5())));
        return res;
    }

    @Override
    public void aliCallback(AliCallBackBo aliCallBackBo) {
        SysOss sysOss = new SysOss();
        sysOss.setFileName(aliCallBackBo.getFilename());
        OssClient storage = OssFactory.instance();
        sysOss.setService(storage.getConfigKey());
        sysOss.setUrl(aliCallBackBo.getFilename());
        baseMapper.insert(sysOss);
    }

    private SysOssVo buildResultEntity(
            String originalfileName, String suffix, String configKey, UploadResult uploadResult) {
        SysOss oss = new SysOss();
        oss.setUrl(uploadResult.getUrl());
        oss.setFileSuffix(suffix);
        oss.setFileName(uploadResult.getFilename());
        oss.setOriginalName(originalfileName);
        oss.setService(configKey);
        baseMapper.insert(oss);
        SysOssVo sysOssVo = BeanUtil.toBean(oss, SysOssVo.class);
        return this.matchingUrl(sysOssVo);
    }

    /**
     * 匹配Url
     *
     * @param oss OSS对象
     * @return oss 匹配Url的OSS对象
     */
    private SysOssVo matchingUrl(SysOssVo oss) {
        OssClient storage = OssFactory.instance(oss.getService());
        // 仅修改桶类型为 private 的URL，临时URL时长为120s
        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
            oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 120));
        }
        return oss;
    }
}
